package linc.cool.framework.protocol.dubbo;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import linc.cool.framework.URL;

/**
 * @author yqlin
 * @date 2022/3/11 4:27 下午
 * @description
 */
public class NettyServer {
    public void start(String hostName, Integer port) {
        // 创建两个线程组bossGroup和workerGroup,含有的子线程NioEventLoop的个数默认为cpu核数的两倍
        // bossGroup只是处理连接请求,真正的和客户端业务处理,会交给workerGroup完成
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        // 创建服务器端的启动对象
        final var bootstrap = new ServerBootstrap();
        // 绑定两个线程池组
        bootstrap.group(bossGroup, workerGroup);
        // 使用NioServerSocketChannel作为服务器的通道实现
        bootstrap.channel(NioServerSocketChannel.class);
        // 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接
        // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
        bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
        bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) {
                ChannelPipeline pipeline = ch.pipeline();
                // 对象解码
                pipeline.addLast(new ObjectDecoder(ClassResolvers.weakCachingResolver(this.getClass().getClassLoader())));
                // 对象编码
                pipeline.addLast(new ObjectEncoder());
                // 对workerGroup的SocketChannel设置处理器
                pipeline.addLast(new NettyServerHandler());
            }
        });
        try {
            // 给cf注册监听器，监听我们关心的事件
            ChannelFuture cf = bootstrap.bind(hostName, port).sync();
            System.out.println("Netty Server start");
            // 对通道关闭进行监听,closeFuture是异步操作,监听通道关闭
            // 通过sync方法同步等待通道关闭处理完毕,这里会阻塞等待通道关闭完成
            cf.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }

    public void start(URL url) {
        this.start(url.getHostname(), url.getPort());
    }
}
